#include "stdafx.h"
#include "SSLServer.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CWinApp theApp;


void LogSSLErrors()
{
  char sError[1024];
  unsigned long nError;
  do
  { 
    nError = ERR_get_error();
    if (nError)
    {
      ERR_error_string(nError, sError);
      printf(sError);
    }
  }
  while (nError);
}

int _tmain()
{
	//initialize MFC (Note we must put up with some /analyze warnings for AfxWinInit even in VC 2008)
	if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
  {
    printf("Failed to initialize MFC\n");
		return 1;
  }

  //Initialise Sockets
  WSADATA wsaData;
  if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) 
  {
    printf("Failed to initialise Winsock, GetLastError:%u\n", ::GetLastError());
    return 2;
  }

  //Standard OpenSSL initialization
  SSL_load_error_strings();
  SSL_library_init();

  //Pick the SSL protocol to use (in this example we just hard code it)
  const SSL_METHOD* pSSLMethod = SSLv3_server_method();

  //Get the default rand file from OpenSSL
  char sSSLFile[1024];
  const char* pszRandFile = RAND_file_name(sSSLFile, sizeof(sSSLFile));
  if (pszRandFile == NULL)
  {
    printf("Failed to get SSL RAND file name\n");
    LogSSLErrors();
    WSACleanup();
    return 3;
  }

  //Set the PRNG for OpenSSL
  RAND_load_file(pszRandFile, -1);
  if (RAND_status() == 0)
  {
    printf("Failed to set SSL RAND file\n");
    LogSSLErrors();
    WSACleanup();
    return 4;
  }

  //Create the SSL context object
  ASSERT(pSSLMethod != NULL);
  SSL_CTX* pSSLContext = SSL_CTX_new(pSSLMethod);
  if (pSSLContext == NULL) 
  {
    printf("Failed to create SSL context\n");
    LogSSLErrors();
    WSACleanup();
    return 5;
  }
  CSSLContext sslContext;
  sslContext.Attach(pSSLContext);

  //Set the certificate to use
  if (SSL_CTX_use_certificate_file(sslContext, "W3MFC.pem", SSL_FILETYPE_PEM) != 1) 
  {
    printf("Failed to set server certificate\n");
    LogSSLErrors();
    WSACleanup();
    return 6;
  }

  //Set the private key to use
  if (SSL_CTX_use_PrivateKey_file(sslContext, "W3MFC.pem", SSL_FILETYPE_PEM) != 1) 
  {
    printf("Failed to set server private key\n");
    LogSSLErrors();
    WSACleanup();
    return 7;
  }

  //Check that we the private key is ok
  if (SSL_CTX_check_private_key(sslContext) != 1) 
  {
    printf("Server private key not valid\n");
    LogSSLErrors();
    WSACleanup();
    return 8;
  }

  //Bind and listen
  CWSocket serverSocket;
  CSSLSocket SSLServerSocket;
  CWSocket clientSocket;
  CSSLSocket SSLClientSocket;
  SOCKADDR_INET clientAddress;
  try
  {
    //Do the low level binding
    serverSocket.CreateAndBind(1234); //Again we just hard code a port number
    serverSocket.Listen();
    int nAddressLength = sizeof(clientAddress);
    serverSocket.Accept(clientSocket, reinterpret_cast<SOCKADDR*>(&clientAddress), &nAddressLength);

    if (!SSLClientSocket.Create(sslContext, clientSocket))
    {
      printf("Failed to create SSL client socket\n");
      LogSSLErrors();
      WSACleanup();
      return 9;
    }

    if (!SSLClientSocket.Accept(5000))
    {
      printf("Failed to accept SSL client connection\n");
      LogSSLErrors();
      WSACleanup();
      return 10;
    }

    //Send the data down the SSL connection
    char* pszResponse = "Hello there client";
    SSLClientSocket.Send(pszResponse, static_cast<int>(strlen(pszResponse)));
    printf("Sending \"%s\" to the client\n", pszResponse);

    SSLClientSocket.Close();
    SSLServerSocket.Close();
  }
  catch(CWSocketException* pEx)
  {
    printf("Unknown socket exception: Error:%d\n", pEx->m_nError);

    pEx->Delete();

    WSACleanup();
    return 12;
  }

  WSACleanup();
	return 0;
}
